#include "spi.h"

#if (SPI_CHANNEL_MODE)
void spi_init(void)
{
#if (CONFIG_SORFWARE_SPI)
    CSN_HIGH();
    CSN_OUTPUT_MODE();

    SCK_LOW();
    SCK_OUTPUT_MODE();
    #if (CONFIG_SPI_MODE == 0)
        SIO_HIGH();
        SIO_OUTPUT_MODE();
    #elif (CONFIG_SPI_MODE == 1)
        MOSI_HIGH();
        MOSI_OUTPUT_MODE();

        MISO_INPUT_MODE();
    #endif
#else
    /**
     * @brief default Mode0(CPOL=0, CPHA=0)
     * 
     */
    #if (SPI_CHANNEL_MODE)
        SET_BIT(CLKCON2, SPI_RST);
        SET_BIT(CLKCON2, SPI_CE);
        MODIFY_REG(SPICON2, 0xFF, (SPI_baud_rate_div_8 | SPI_DATA_SIZE_8));
        MODIFY_REG(SPICON0, 0x2F, (SPI_first_bit_LSB | SPI_CPHA_1Edge | SPI_CPOL_low | SPI_OPEN_EN | SPI_EN));
        // spi FIFO reset
        SET_BIT(SPIFCON, SPI_FIFO_RST);
        // // enable interrupt
        // SET_BIT(SPIINTEN, (SPI_RX_FIFO_INT | SPI_TX_FIFO_INT));
        #if (CONFIG_SPI_MODE == 0)
            SET_BIT(SPICON1, SPI_HD_MODE);
        #endif
    #endif
#endif
}

/* spi_write_reg, Write data(1 Byte Address ,1 byte data) */
void spi_write_reg(uint8_t reg,  uint8_t val)
{
#if (CONFIG_SORFWARE_SPI)
    CSN_LOW();
    spi_ww(reg);
    spi_ww(val);
    CSN_HIGH();
#else
    #if (SPI_CHANNEL_MODE)
        spi_ww(reg);
        spi_ww(val);
    #endif
#endif
}

/* spi_write_buf, Write Buffer */
void spi_write_buf(uint8_t reg, uint8_t *buf, uint8_t len)
{
#if (CONFIG_SORFWARE_SPI)
    uint8_t i;
    
    CSN_LOW();
    spi_ww(reg);
    for (i = 0; i < len; i++)
        spi_ww(buf[i]);
    CSN_HIGH();
#else
    #if (SPI_CHANNEL_MODE)
        uint8_t i;

        spi_ww(reg);
        for (i = 0; i < len; i++) {
            while (!SPI_TX_FIFO_SEND_OK());
            spi_ww(buf[i]); 
        }

    #endif
#endif

}

/* spi_read_reg, Read Data(1 Byte Address ,1 byte data return) */
uint8_t spi_read_reg(uint8_t reg)
{
#if (CONFIG_SORFWARE_SPI)
    uint8_t val;
    
    CSN_LOW();
    spi_wr(reg);
    val = spi_read_byte();
    #if (CONFIG_SPI_MODE == 0)
        SIO_OUTPUT_MODE();
    #endif
    CSN_HIGH();
    
    return val;
#else
    #if (SPI_CHANNEL_MODE)
        uint8_t val;

        spi_wr(reg);
        val = spi_read_byte();

        return val;
    #endif
#endif
}

/* spi_read_buf, Read Data(1 Byte Address ,length byte data read) */
void spi_read_buf(uint8_t reg, uint8_t *buf, uint8_t len)
{
#if (CONFIG_SORFWARE_SPI)
    uint8_t i;

    CSN_LOW();                                                                   
    spi_wr(reg);                                                                       
    for (i = 0; i < len; i++)
        buf[i] = spi_read_byte();
    #if (CONFIG_SPI_MODE == 0)
        SIO_OUTPUT_MODE();
    #endif
    CSN_HIGH();    
#else
    #if (SPI_CHANNEL_MODE)
        uint8_t i;
        spi_wr(reg);

        for (i = 0; i < len; i++) {
            while (SPI_RX_FIFO_NO_EMPTY());
            buf[i] = spi_read_byte();
        }
    #endif
#endif
                                           
}

void spi_cs_low(void)
{
#if (CONFIG_SORFWARE_SPI)
    CSN_LOW();
#else
    #if (SPI_CHANNEL_MODE)
    /** TODO: **/
    #endif
#endif
}

void spi_cs_high(void)
{
#if (CONFIG_SORFWARE_SPI)
    CSN_HIGH();
#else
    #if (SPI_CHANNEL_MODE)
    /** TODO: **/
    #endif
#endif
}

void spi_exit(void)
{
}


/* spi_ww, SPI Write a byte for write register */
void spi_ww(uint8_t r_reg)
{
#if (CONFIG_SORFWARE_SPI)
    uint8_t  i;
    
    for (i = 0; i < 8; i++) {
        SCK_LOW();
        
    #if (CONFIG_SPI_MODE == 0)
        if (r_reg & 0x80)
            SIO_HIGH();
        else
            SIO_LOW();
    #elif (CONFIG_SPI_MODE == 1)
        if (r_reg & 0x80)
            MOSI_HIGH();
        else
            MOSI_LOW();
    #endif
        r_reg <<= 1;
      
        SCK_HIGH();
    }
   SCK_LOW();
#else
    #if (SPI_CHANNEL_MODE)
         SPITXD = r_reg;
    #endif
#endif

}

/* spi_wr, SPI Write a byte for read regiset */
void spi_wr(uint8_t r_reg)
{
#if (CONFIG_SORFWARE_SPI)
    uint8_t  i;
    
    for(i = 0; i < 8; i++) {
        SCK_LOW();
    #if (CONFIG_SPI_MODE == 0)
        if (r_reg & 0x80)
            SIO_HIGH();
        else
            SIO_LOW();
    #elif (CONFIG_SPI_MODE == 1)
        if (r_reg & 0x80)
            MOSI_HIGH();
        else
            MOSI_LOW();
    #endif
        r_reg <<= 1;
      
        SCK_HIGH();
    }
#if (CONFIG_SPI_MODE == 0)
   SIO_INPUT_MODE();
#endif
   SCK_LOW();
#else
    #if (SPI_CHANNEL_MODE)
         SPITXD = r_reg;
    #endif
#endif
}

uint8_t spi_read_byte(void)
{
#if (CONFIG_SORFWARE_SPI)
    uint8_t i, val;
    
    val = 0;
    
    for (i = 0; i < 8; i++) {
        SCK_LOW();
        val <<= 1;
        SCK_HIGH();
    #if (CONFIG_SPI_MODE == 0)
        if (SIO_STATUS())
          val |= 0x01;
    #elif (CONFIG_SPI_MODE == 1)
        if (MISO_STATUS())
          val |= 0x01;
    #endif
        
    }
    SCK_LOW();
    
    return val;
#else
    #if (SPI_CHANNEL_MODE)
        uint8_t val;
        val = SPIRXD;
        return val;
    #endif
#endif
}

void spi_select_ss(spi_nss_select ss)
{
#if (CONFIG_SORFWARE_SPI)
    /**
     * @brief do change ss
     * 
     */
#else
    #if (SPI_CHANNEL_MODE)
        /**
         * @brief change hardware select
         * 1. change input
         * 2. enable other ss
         * 
         */
        if (ss == first_spi) {
            _P20_EN(SET);
            _P20_IO_OUTPUT();
            _P20_IO_MODE();
            MODIFY_EFR_REG(EXTMFP4, 0x38, 0x30);    // change P30
        } else if (ss == sencond_spi) {
            _P30_EN(SET);
            _P30_IO_OUTPUT();
            _P30_IO_MODE();
            MODIFY_EFR_REG(EXTMFP2, 0x03, 0x01);    // change P20
        }

            
    #endif
#endif
}
#endif